/*
 * MesoscopicTrafficSimulation.cpp
 *
 *  Created on: 12/10/2011
 *      Author: godinho
 */

#include <evolutive/impl/MesoscopicTrafficSimulation.h>
#include <evolutive/impl/MesoscopicNetworkBuilder.h>
#include <XMLOutputMesoscopicInterface.h>
#include <Network.h>
#include <SimulationNode.h>
#include <NodeInput.h>
#include <TLSPhase.h>
#include <TLSLink.h>
#include <Controller.h>
#include <localview/Node.h>
#include <localview/Phase.h>
#include <localview/Link.h>
#include <localview/Network.h>
#include <vector>
#include <math.h>
#include <defaults.h>
#include <iostream>

typedef MesoscopicTrafficSimulation::SimulationInterfaceImpl simulationInterfaceImpl;

class CompoundSimulationOutput : public SimulatorOutput {
public:
    CompoundSimulationOutput() {

    }

    ~CompoundSimulationOutput() {

    }

    virtual void startSimulation(Network* network) {
        for(int i = 0; i < mSimulatorOutputVector.size(); i++) {
            mSimulatorOutputVector[i]->startSimulation(network);
        }
    }

    virtual void endSimulation(Network* network) {
        for(int i = 0; i < mSimulatorOutputVector.size(); i++) {
            mSimulatorOutputVector[i]->endSimulation(network);
        }
    }

    virtual void startStep(int step, Network* network) {
        for(int i = 0; i < mSimulatorOutputVector.size(); i++) {
            mSimulatorOutputVector[i]->startStep(step, network);
        }
    }

    virtual void endStep(int step, Network* network) {
        for(int i = 0; i < mSimulatorOutputVector.size(); i++) {
            mSimulatorOutputVector[i]->endStep(step, network);
        }
    }

    void addSimulatorOutput(SimulatorOutput* out) {
        mSimulatorOutputVector.push_back(out);
    }

private:
    std::vector<SimulatorOutput*> mSimulatorOutputVector;
};

MesoscopicTrafficSimulation::MesoscopicTrafficSimulation() {
	mControler = 0;
	mLogEnabled = 0;
	mFileGen = 0;
}

MesoscopicTrafficSimulation::~MesoscopicTrafficSimulation() {
}

void MesoscopicTrafficSimulation::simulate(std::vector<Case*> cases, localview::LocalView* lv, int timesteps, int phaseId) {
	for(unsigned int i = 0; i < cases.size(); i++) {
		simulateCase(cases[i], lv, timesteps, phaseId);
	}
}

void MesoscopicTrafficSimulation::simulateCase(Case* c, localview::LocalView* lv, int timesteps, int phaseId) {
	if(mControler) {
		delete mControler;
	}

	Network* net = buildSimulationEnvironment(lv, c, phaseId);
	CompoundSimulationOutput output;

//	if(mLogEnabled) {
#ifdef DEBUG
	    XMLOutputMesoscopicInterface xmlOut("simulation.xml");
	    output.addSimulatorOutput(&xmlOut);
#endif
//	}

    mSimulationInterface = new SimulationInterfaceImpl(c);
    output.addSimulatorOutput(mSimulationInterface);

	mControler = new Controller(net);
	mControler->setOutput(&output);
	mControler->startSimulation(timesteps);

	delete net;
}

void MesoscopicTrafficSimulation::stopSimulation() {
	mControler->stopSimulation();
	mControler = 0;
}

Network* MesoscopicTrafficSimulation::buildSimulationEnvironment(localview::LocalView* lv, Case* c, int phaseId) {

	MesoscopicNetworkBuilder* netBuilder = new MesoscopicNetworkBuilder();

	Network* net = netBuilder->lvNetwork2Mesoscopic(lv, c, phaseId);
	delete netBuilder;

	return net;
}

void MesoscopicTrafficSimulation::enableLog() {
    mLogEnabled = true;
}

simulationInterfaceImpl::SimulationInterfaceImpl(Case* c) {
    mCase = c;
    mLocalQueue = 0;
    mSideQueue = 0;
    mNextQueue = 0;
    mNextSideQueue = 0;
    mNumSteps = 0;
}

simulationInterfaceImpl::~SimulationInterfaceImpl() {

}

void simulationInterfaceImpl::startStep(int step, Network* network) {

    //Local queue
    mLocalQueue += network->getLocalQueue()->getQueueSize()/network->getLocalQueue()->getNumLanes();

    //Side queue
    std::vector<NodeInput*> vSideQueues = network->getSideQueues();
    for(unsigned int i = 0; i < vSideQueues.size(); i++) {
        mSideQueue += (vSideQueues[i])->getQueueSize()/(vSideQueues[i]->getNumLanes());
    }

    //Next queue
    mNextQueue += network->getNextQueue()->getQueueSize()/network->getNextQueue()->getNumLanes();

    //Next side queue
    std::vector<NodeInput*> vNextSideQueues = network->getNextSideQueues();
    for(unsigned int i = 0; i < vNextSideQueues.size(); i++) {
         mNextSideQueue += (vNextSideQueues[i])->getQueueSize()/(vNextSideQueues[i])->getNumLanes();
     }

    mNumSteps++;
}

void simulationInterfaceImpl::endStep(int step, Network* network) {



}

void simulationInterfaceImpl::startSimulation(Network* network) {
}

void simulationInterfaceImpl::endSimulation(Network* network) {
    mNumSteps = mNumSteps < 1 ? 1 : mNumSteps;
    mCase->setResultLocalQueue(mLocalQueue/mNumSteps);
    mCase->setResultLocalSideQueue(mSideQueue/mNumSteps);
    mCase->setResultNextQueue(mNextQueue/mNumSteps);
    mCase->setResultNextSideQueue(mNextSideQueue/mNumSteps);
}
